/**
 * Copyright (c) 2017-2017 All Rights Reserved.
 */
package com.zbest.zpay.gw.assemble.wx;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import com.zbest.zpay.gw.assemble.MessageAssemble;
import com.zbest.zpay.gw.assemble.alipay.MD5;
import com.zbest.zpay.gw.cache.ChannelEncryptConfigCache;
import com.zbest.zpay.gw.cache.ChannelPayConfigCache;
import com.zbest.zpay.gw.cache.CommunicationConfigCache;
import com.zbest.zpay.gw.dal.model.GwChannelEncryptConfigDO;
import com.zbest.zpay.gw.dal.model.GwCommunicationConfigDO;
import com.zbest.zpay.gw.model.MessageContext;
import com.zbest.zpay.gw.model.SecretKeyType;
import com.zbest.zpay.masterdata.cache.ChannelConfigCache;
import com.zbest.zpay.masterdata.dal.model.ChannelConfigDO;

/**
 * 
 *
 * @author Administrator
 * @version $Id: AbstractAlipayMessageAssemble.java, v 0.1 2017-4-27 下午11:42:52 Administrator Exp $
 */
public abstract class AbstractWxMessageAssemble implements MessageAssemble {

    @Resource
    protected ChannelEncryptConfigCache channelEncryptConfigCache;

    @Resource
    protected ChannelPayConfigCache     channelPayConfigCache;

    @Resource
    protected CommunicationConfigCache  communicationConfigCache;

    @Resource
    protected ChannelConfigCache        channelConfigCache;

    /** 
     * @see com.zbest.zpay.gw.assemble.MessageAssemble#buildRequest(com.zbest.zpay.gw.model.MessageContext)
     */
    @Override
    public void buildRequest(MessageContext messageContext) {

        //1.获取原始参数
        Map<String, String> paramMap = buildOriginParam(messageContext);

        //2.去除空的和null的参数
        paramMap = paramFilter(paramMap);

        //3.加入签名密文
        fillSignData(paramMap, messageContext.getChannelId());

        //4.构造表单
        String message = buildRequestMessage(messageContext, paramMap);
        messageContext.setSendMessage(message);
    }

    protected abstract Map<String, String> buildOriginParam(MessageContext context);

    protected abstract String buildRequestMessage(MessageContext context, Map<String, String> data);

    /** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    private Map<String, String> paramFilter(Map<String, String> sArray) {

        Map<String, String> result = new HashMap<String, String>();

        if (sArray == null || sArray.size() <= 0) {
            return result;
        }

        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }

        return result;
    }

    /** 
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    private String buildSignPlainText(Map<String, String> params) {

        String[] arrayToSort = params.keySet().toArray(new String[params.size()]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);

        String prestr = "";

        for (String field : arrayToSort) {
            String value = params.get(field);
            prestr = prestr + field + "=" + value + "&";
        }

        return prestr;
    }

    /**
     * 填充签名数据
     * @param paramMap 请求前的参数数组
     * @return 要请求的参数数组
     */
    private void fillSignData(Map<String, String> paramMap, String channelId) {

        ChannelConfigDO channelConfigDO = channelConfigCache.get(channelId);

        /**FIXME 通过channelid和SecretKeyType找到算法名*/
        GwChannelEncryptConfigDO channelEncryptConfigDO = channelEncryptConfigCache.get(
            channelConfigDO.getChannelSystemId(), SecretKeyType.SIGN.name());

        GwCommunicationConfigDO communicationConfigDO = communicationConfigCache.get(channelId);

        String plainStr = buildSignPlainText(paramMap); //把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        if (channelEncryptConfigDO.getEncryptAlgorithm().equals("MD5")) {
            mysign = MD5.sign(plainStr, channelEncryptConfigDO.getSecretKeyContent(),
                communicationConfigDO.getCharset());
        }

        //签名结果与签名方式加入请求提交参数组中
        paramMap.put("sign", mysign);
        paramMap.put("sign_type", channelEncryptConfigDO.getEncryptAlgorithm());

    }

}
